#pragma once
// -------------------------------------------------
// ZED Kit
// -------------------------------------------------
//   File Name: signal.hpp
//      Author: Ziming Li
//     Created: 2021-03-01
// -------------------------------------------------
// Copyright (C) 2021 MingYang Software Technology.
// -------------------------------------------------

#ifndef ZED_THREADING_SIGNAL_HPP
#define ZED_THREADING_SIGNAL_HPP

#include "../platform_sdk.h"
#if defined(_Z_OS_WINDOWS)
#   include "../win/handled_resource.hpp"
#elif defined(_Z_OS_POSIX)
#   include <pthread.h>
#endif

namespace zed {

#if defined(_Z_OS_WINDOWS)
class signal : unique_resource<HANDLE>
{
public:
    signal(void) : unique_resource(::CreateEvent(nullptr, TRUE, FALSE, nullptr)) {}

    void reset(void) { ::ResetEvent(get()); }
    void notify(void) { ::SetEvent(get()); }
    void wait(void) { ::WaitForSingleObject(get(), INFINITE); }
};
#elif defined(_Z_OS_POSIX)
class signal
{
public:
    signal(void);
    ~signal(void);

    void reset(void) { set_flag(false); }
    void notify(void);
    void wait(void);
private:
    void set_flag(bool flag);

    bool m_flag = false;
    pthread_mutex_t m_mutex;
    pthread_cond_t m_cond;
};
#endif // _Z_OS_WINDOWS

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Implementations

#ifdef _Z_OS_POSIX
inline signal::signal(void)
{
    pthread_mutex_init(&m_mutex, nullptr);
    pthread_cond_init(&m_cond, nullptr);
}

inline signal::~signal(void)
{
    pthread_cond_destroy(&m_cond);
    pthread_mutex_destroy(&m_mutex);
}

inline void signal::notify(void)
{
    set_flag(true);
    pthread_cond_signal(&m_cond);
}

inline void signal::set_flag(bool flag)
{
    pthread_mutex_lock(&m_mutex);
    m_flag = flag;
    pthread_mutex_unlock(&m_mutex);
}

inline void signal::wait(void)
{
    pthread_mutex_lock(&m_mutex);
    while (!m_flag)
        pthread_cond_wait(&m_cond, &m_mutex);
    pthread_mutex_unlock(&m_mutex);
}
#endif // _Z_OS_POSIX

} // namespace zed

#endif // ZED_THREADING_SIGNAL_HPP
